<template>
	<div class="attachment-content">
		<div class="attachment-content-left">
			<div class="cate-list flex-1 mb-[10px]">
				<el-scrollbar>
					<el-tree
						:data="attachmentCategory.data"
						default-expand-all
						node-key="id"
						:highlight-current="true"
						:current-node-key="attachmentCategory.currentId"
						:props="defaultTreeProps"
						:ref="attachmentCategoryTree"
						@node-click="handleCatSelect"
					>
						<template #default="{ node, data }">
							<div class="cate-item flex">
								<SvgIcon name="local-icon-folder" :size="18" v-if="data.pid ? false : true" class="w-[15px] h-[16px] mr-2" />
								<div class="flex-1 leading-[16px] max-w-[100px] truncate" @click="attachment.queryParams.cid = data.id">{{ node.label }}</div>
								<el-dropdown v-if="data.id > 0" :hide-on-click="false">
									<span v-if="data.id ? true : false" class="muted ml-10 float-right mr10">···</span>
									<template #dropdown>
										<el-dropdown-menu>
											<el-dropdown-item v-if="data.id ? true : false" @click="updateAttachmentCategory(data.id, node.label)"
												>编辑分类</el-dropdown-item
											>
											<el-dropdown-item v-if="data.id ? true : false" @click="deleteAttachmentCategory(data.id)">删除分类</el-dropdown-item>
										</el-dropdown-menu>
									</template>
								</el-dropdown>
							</div>
						</template>
					</el-tree>
				</el-scrollbar>
			</div>
			<!-- 添加分类 -->
			<popover-input class="ml-[40px]" placeholder="请输入分类名称" @click="addAttachmentCategory(0)">
				<el-button>添加分类</el-button>
			</popover-input>
		</div>
		<!-- 素材 -->
		<div class="attachment-list-wrap flex flex-col p-[15px] flex-1 overflow-hidden">
			<el-row :gutter="15" class="h-[32px]">
				<el-col :span="12">
					<div class="flex">
						<el-upload v-bind="upload" ref="uploadRef" :show-file-list="false">
							<el-button type="primary">上传{{ getAccept['desc'] }}</el-button>
						</el-upload>

						<el-button class="ml-[15px]" :disabled="batchOperateDisabled" @click="deleteAttachmentEvent()">删除</el-button>
						<el-button class="ml-[15px]" :disabled="batchOperateDisabled" @click="moveAttachmentEvent()">移动</el-button>
					</div>
				</el-col>
				<el-col :span="12" class="text-right">
					<el-input :class="scene == 'attachment'?'!w-[300px]':''" placeholder="请输入名称" v-model="attachment.queryParams.name" @keyup.enter="getAttachmentList">
						<template #append>
							<el-button @click="getAttachmentList">
								<template #icon>
									<el-icon class="el-input__icon"><ele-Search /></el-icon>
								</template>
							</el-button>
						</template>
					</el-input>
				</el-col>
			</el-row>
			<div class="flex-1 my-[15px] h-0" v-loading="attachment.loading">
				<el-scrollbar>
					<!-- 选择弹出框 -->
					<div class="flex flex-wrap" v-if="attachment.tableList.length">
						<div class="attachment-item mr-[10px] w-[100px]" v-for="(item, index) in attachment.tableList" :key="index">
							<div
								class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[100px]"
								@click="selectFile(item)"
							>
								<el-image :src="item.uri" fit="contain" v-if="type == 'image'"></el-image>
								<video :src="item.uri" v-if="type == 'video'"></video>
								<div class="h-[100px] w-[100px] flex justify-center items-center" v-else-if="type == 'file'">
									<SvgIcon :name="getFileIcon(item.name)" :size="60" class="w-[60px] h-[60px]" />
								</div>
								<el-badge :value="item.order_num" type="primary" class="item-selected-badge" v-show="selectedFile[item.id] && limit > 1"></el-badge>
								<div class="item-selected" v-show="selectedFile[item.id]">
									<SvgIcon name="ele-Select" size="30" color="#fff" />
								</div>
							</div>
							<div class="flex items-center relative h-[54px]">
								<el-tooltip placement="top">
									<template #content>{{ item.name }}</template>
									<div class="truncate mb-[10px] cursor-pointer text-base flex-1 text-center">{{ item.name }}</div>
								</el-tooltip>
								<div class="attachment-action">
									<span class="ml-[4px]" @click="deleteAttachmentEvent(index)">删除</span>
									<span class="ml-[10px]" @click="renameFile(index, item.name)">改名</span>
									<span class="ml-[10px]" v-if="item.type == 1" @click="previewImage(index)">查看</span>
									<span class="ml-[10px]" v-if="item.type == 2" @click="previewVideo(index)">查看</span>
									<span class="ml-[10px]" v-if="item.type == 3" v-down="downloadFile(index)">下载</span>
								</div>
							</div>
						</div>
					</div>
					<div class="flex items-center justify-center" v-else>
						<el-empty v-if="!attachment.loading" description="暂无数据，请上传文件" :image-size="100" />
					</div>
				</el-scrollbar>
			</div>
			<el-row :gutter="20">
				<el-col :span="6" class="leading-[32px]" :class="scene == 'attachment'?'text-[14px]':''">
					<span class="mr5">已选择 {{ selectedFileCount.num }} 个</span>
					<el-button key="primary" type="primary" link class="delete-all-btn" :class="scene == 'attachment'?'!text-[14px]':''" @click="clearSelected()">清空</el-button>
				</el-col>
				<el-col :span="18">
					<div class="flex h-full justify-end items-center">
						<el-pagination
							v-model:current-page="attachment.tableParams.page_num"
							:small="pageData.small"
							v-model:page-size="attachment.tableParams.page_limit"
							:page-sizes="pageData.page_sizes"
							:layout="pageData.layout"
							:total="attachment.tableParams.page_total"
                            :pager-count="pageData.pager_count"
							@size-change="getAttachmentList()"
							@current-change="getAttachmentList"
						/>
					</div>
				</el-col>
			</el-row>
		</div>
		<!-- 分类弹框 -->
		<el-dialog v-model="attachmentCategory.visible" :title="attachmentCategory.title" width="400px">
			<el-form label-width="100px" class="p-5">
				<el-form-item label="上级分类：" v-if="attachmentCategory.type == 'add'" class="!mb-[18px]">
					<el-cascader
						class="w-[200px]"
						:options="attachmentCategorySelect.selectData"
						:props="defaultSelectTreeProps"
						:v-model="[attachmentCategorySelect.defaultSelectId]"
						@change="attachmentCategoryChange"
						placeholder="请选择分类"
					/>
				</el-form-item>
				<el-form-item label="分类名称：">
					<div class="w-[200px]">
						<el-input v-model="attachmentCategory.name" placeholder="请输入分类名称" clearable></el-input>
					</div>
				</el-form-item>
			</el-form>
			<template #footer>
				<span class="dialog-footer">
					<el-button @click="attachmentCategory.visible = false">取消</el-button>
					<el-button type="primary" @click="attachmentCategory.type == 'add' ? attachmentCategory.addConfirm() : attachmentCategory.updateConfirm()"
						>确认</el-button
					>
				</span>
			</template>
		</el-dialog>
		<!-- 附件重命名 -->
		<el-dialog v-model="renameAttachmentData.visible" title="附件重命名" width="400px">
			<el-form label-width="80px" class="p-5">
				<el-form-item label="附件名称">
					<el-input v-model="renameAttachmentData.name" placeholder="请输入附件名称" clearable></el-input>
				</el-form-item>
			</el-form>
			<template #footer>
				<span class="dialog-footer">
					<el-button @click="renameAttachmentData.visible = false">取消</el-button>
					<el-button type="primary" :loading="renameAttachmentData.loading" @click="renameAttachmentData.confirm()">确认</el-button>
				</span>
			</template>
		</el-dialog>
		<!-- 移动附件分类 -->
		<el-dialog v-model="moveAttachmentData.visible" title="移动分类" width="400px">
			<el-form label-width="80px" class="p-5">
				<el-form-item label="移动至" style="margin-bottom: 0">
					<el-cascader
						:options="attachmentCategorySelect.selectData"
						:props="defaultSelectTreeProps"
						placeholder="请选择分类"
						@change="moveAttachmentChange"
					/>
				</el-form-item>
			</el-form>
			<template #footer>
				<span class="dialog-footer">
					<el-button @click="moveAttachmentData.visible = false">取消</el-button>
					<el-button type="primary" :loading="moveAttachmentData.loading" @click="moveAttachmentData.confirm()">确认</el-button>
				</span>
			</template>
		</el-dialog>
		<!-- 图片预览 -->
		<el-image-viewer
			:url-list="previewImageList"
			v-if="imageViewer.show"
			@close="imageViewer.show = false"
			:initial-index="imageViewer.index"
			:zoom-rate="1"
		/>
		<!-- 视频预览 -->
		<el-dialog v-model="videoViewer.visible" width="60%" align-center :destroy-on-close="true" custom-class="video-preview">
			<videoPlayer :src="videoViewer.src" width="100%" />
		</el-dialog>
	</div>
</template>

<script lang="ts">
import { ref, reactive, watch, computed, onMounted, toRaw, defineComponent } from 'vue';
import { fileCateLists, fileList, fileCateAdd, fileCateEdit, fileCateDelete, fileDelete, fileMove, fileRename } from '/@/api/file';
import { UploadFile } from 'element-plus';
import { messageBox, messageError } from '/@/utils/message';
import { Local } from '/@/utils/storage';
import { getFileInfo, getUrl } from '/@/utils/util';
const { VITE_API_URL } = import.meta.env;

export default defineComponent({
	name: 'attachemnt',
	props: {
		// 选择数量限制
		limit: {
			type: Number,
			default: 2,
		},
        // 类型
		type: {
			type: String,
			default: 'image',
		},
        // 接受上传类型
        accept: {
			type: String,
			default: '*/*',
		},
        // 限制上传大小，单位KB
        size: {
			type: Number,
			default: 0,
		},
		// 场景
		scene: {
			type: String,
			default: 'select', // select 选择图片 attachment 素材中心
		},
	},
	setup(props) {
		/** 数据 **/

		// 是否显示
		const operate = ref(true);

		// 类型
		const getAccept = computed(() => {
			switch (props.type) {
				case 'image':
					return { desc: '图片', type: 1 };
				case 'video':
					return { desc: '视频', type: 2 };
				default:
					return { desc: '文件', type: 3 };
			}
		});

		// 选中的文件
		const selectedFile: Record<string, any> = reactive({});

		// 选中的文件排序
		const selectedFileOrder = reactive({});

		// 选中的文件
		const selectedFileCount = reactive({ num: 0 });

		// 全选
		const selectAll = ref(false);

		// 附件分类数据
		const attachmentCategory: Record<string, any> = reactive({
			data: [],
			type: '', // add 添加 update 修改
			title: '', // 弹框标题
			name: '', // 分类名称
			cateId: 0, // 分类id
			visible: false, // 是否显示
			currentId: '', //分类当前选中
		});

		// 附件分类下拉数据
		const attachmentCategorySelect = reactive({
			selectData: [],
			defaultSelectId: 0, //默认选中
			currentSelectId: 0, //当前选中
		});

		const attachmentCategoryTree = ref(null);

		// 导航树默认
		const defaultTreeProps = {
			label: 'name',
		};

		// 导航树下拉默认
		const defaultSelectTreeProps = {
			label: 'name',
			value: 'id',
		};

		// 附件列表数据
		const attachment = reactive<TableDataState>({
			loading: false,
			tableList: [],
			queryParams: {
				name: '',
				cid: '',
				type: 0,
			},
			tableParams: {
				page_num: 1,
				page_limit: 15,
				page_total: 0 as any,
			},
		});

		// 分页数据
		const pageData = reactive({
			page_sizes: [10, 20, 30, 40, 60],
			layout: 'total, sizes, prev, pager, next',
			pager_count: 6,
			small:true
		});

		attachment.tableParams.page_limit = 10;
		attachment.queryParams.type = getAccept.value['type'];

		// 上传文件
		const uploadRef = ref<Record<string, any> | null>(null);

		// 重命名附件数据
		const renameAttachmentData: Record<string, any> = reactive({
			name: '',
			loading: false,
			visible: false,
		});

		// 移动附件数据
		const moveAttachmentData: Record<string, any> = reactive({
			cid: '',
			loading: false,
			visible: false,
		});

		// 批量操作是否可操作
		const batchOperateDisabled = ref(true);

		// 图片预览
		const imageViewer = reactive({
			show: false,
			index: 0,
		});

		// 视频预览
		const videoViewer = reactive({
			visible: false,
			src: '',
		});

		/** 方法 **/

		//场景初始化
		const initScene = () => {
			if(props.scene == 'attachment') {
				attachment.tableParams.page_limit = 30;
				pageData.small = false;
			}
		}

		// 获取分类列表
		const getAttachmentCategoryList = async () => {
			let res = await fileCateLists({ type: getAccept.value['type'] });
			const item: any[] = [
				{
					id: '',
					name: '全部',
				},
				{
					id: 0,
					name: '未分类',
				},
			];

			attachmentCategory.data = JSON.parse(JSON.stringify(res));
			attachmentCategory.data.unshift(...item);
			const selectItem: any[] = [
				{
					id: 0,
					name: '顶级分类',
				},
			];

			attachmentCategorySelect.selectData = JSON.parse(JSON.stringify(res));
			attachmentCategorySelect.selectData.unshift(...selectItem);
		};

		// 添加分类
		const addAttachmentCategory = (pid: number) => {
			attachmentCategory.type = 'add';
			attachmentCategory.title = '添加分类';
			attachmentCategory.visible = true;
			attachmentCategory.name = '';
			attachmentCategorySelect.defaultSelectId = pid;
			attachmentCategory.addConfirm = async () => {
				await fileCateAdd({ type: getAccept.value['type'], pid: attachmentCategorySelect.currentSelectId, name: attachmentCategory.name });
				attachmentCategory.visible = false;
				getAttachmentCategoryList();
			};
		};

		// 编辑分类
		const updateAttachmentCategory = (id: number, name: string) => {
			attachmentCategory.type = 'update';
			attachmentCategory.title = '编辑分类';
			attachmentCategory.visible = true;
			attachmentCategory.name = name;
			attachmentCategory.updateConfirm = async () => {
				await fileCateEdit({ id: id, name: attachmentCategory.name });
				attachmentCategory.visible = false;
				getAttachmentCategoryList();
			};
		};

		// 删除分类
		const deleteAttachmentCategory = async (id: number) => {
			messageBox('确定要删除该分类吗？').then(async () => {
				await fileCateDelete({ id: id });
				getAttachmentCategoryList();
			});
		};

		// 选择器分类
		const attachmentCategoryChange = (value) => {
			attachmentCategorySelect.currentSelectId = value[0];
		};

		// 分类选中
		const handleCatSelect = (item: any) => {
			attachment.queryParams.cid = item.id;
		};

		// 获取附件列表
		const getAttachmentList = (page: number = 1) => {
			attachment.loading = true;
			attachment.tableParams.page_num = page;
            if (props.accept && props.accept != '*/*') attachment.queryParams.ext = props.accept.split('.').join('').split(',')
            if (props.size) attachment.queryParams.size = props.size;
			fileList({
				page_num: attachment.tableParams.page_num,
				page_limit: attachment.tableParams.page_limit,
				...attachment.queryParams,
			})
			.then((res) => {
				attachment.tableList = res.list;
				attachment.tableParams.page_total = res.page_total;
				attachment.loading = false;
				clearSelected();
				for (let i = 0; i < attachment.tableList.length; i++) {
					attachment.tableList[i]['image_list'] = [];
					attachment.tableList[i]['image_list'].push(res.list[i]['uri']);
				}
			})
			.catch(() => {
				attachment.loading = false;
			});
		};

		// 上传文件
		const upload = computed(() => {
			return {
				action: `${VITE_API_URL}/admin/upload/${props.type}`,
				multiple: true,
                accept: props.accept,
				data: {
					cid: attachment.queryParams.cid,
				},
				headers: {
					Authorization: Local.get('token'),
				},
				onSuccess: (response: any, uploadFile: UploadFile) => {
					if (response.code == 0) {
						getAttachmentList();
						uploadRef.value?.handleRemove(uploadFile);
					} else {
						uploadFile.status = 'fail';
						messageError(response.msg);
					}
				},
			};
		});

		// 清空选中
		const clearSelected = () => {
			const keys = Object.keys(toRaw(selectedFile));
			if (keys.length) {
				keys.forEach((key) => {
					delete selectedFileOrder[selectedFile[key].order_num];
					delete selectedFile[key];
				});
				selectAll.value = false;
			}
			selectedFileCount.num = 0;
		};

		// 选择附件
		const selectFile = (data: any) => {
			const keys = Object.keys(toRaw(selectedFile));
			let length = keys.length;

			if (selectedFile[data.id]) {
				delete selectedFile[data.id];
				if (props.limit > 1) {
					delete selectedFileOrder[data.order_num];
					// 清空后重新循环排序
					const keys = Object.keys(toRaw(selectedFileOrder));
					if (keys.length) {
						keys.forEach((key, index) => {
							selectedFileOrder[index + 1] = selectedFileOrder[key];
							selectedFile[selectedFileOrder[key]].order_num = index + 1;
							if (parseInt(key) > keys.length) delete selectedFileOrder[key];
						});
					}
				}
				selectedFileCount.num = length - 1;
			} else {
				if (props.limit == 1 && length == props.limit) {
					delete selectedFile[keys[0]];
				} else if (length >= props.limit) {
					messageError('可选数量已达上限');
					return;
				}

				if (props.limit > 1) {
					data.order_num = length + 1;
					selectedFileOrder[length + 1] = data.id;
				} else {
					data.order_num = 1;
					length = 0;
				}
				selectedFile[data.id] = toRaw(data);
				selectedFileCount.num = length + 1;
			}
		};

		// 删除附件
		const deleteAttachmentEvent = (index: number | null = null) => {
			const ids = index === null ? Object.keys(toRaw(selectedFile)) : [attachment.tableList[index].id];
			messageBox('确定要删除所选附件吗？如所选附件已被使用,删除将会受到影响，请谨慎操作！').then(async () => {
				await fileDelete({ ids: ids });
				getAttachmentList();
			});
		};

		// 重命名附件
		const renameFile = (index: number | null = null, name: string) => {
			const id = index === null ? Object.keys(toRaw(selectedFile)) : attachment.tableList[index].id;
			renameAttachmentData.visible = true;
			renameAttachmentData.name = name;
			renameAttachmentData.confirm = () => {
				renameAttachmentData.loading = true;
				fileRename({ id: id, name: renameAttachmentData.name })
					.then(() => {
						renameAttachmentData.visible = false;
						renameAttachmentData.loading = false;
						getAttachmentList();
					})
					.catch(() => {
						renameAttachmentData.loading = false;
					});
			};
		};

		// 移动附件
		const moveAttachmentEvent = (index: number | null = null) => {
			const ids = index === null ? Object.keys(toRaw(selectedFile)) : [attachment.tableList[index].id];
			moveAttachmentData.visible = true;
			moveAttachmentData.confirm = () => {
				moveAttachmentData.loading = true;
				fileMove({ cid: moveAttachmentData.cid, ids: ids })
					.then(() => {
						moveAttachmentData.visible = false;
						moveAttachmentData.loading = false;
						getAttachmentList();
					})
					.catch(() => {
						moveAttachmentData.loading = false;
					});
			};
		};

		// 选择器分类
		const moveAttachmentChange = (value) => {
			moveAttachmentData.cid = value[0];
		};

		// 预览图片
		const previewImage = (index: number) => {
			imageViewer.show = true;
			imageViewer.index = index;
		};

		// 预览图片列表
		const previewImageList = computed(() => {
			return toRaw(attachment.tableList).map((item: Record<string, any>) => {
				return item.uri;
			});
		});

		// 预览视频
		const previewVideo = (index: number) => {
			videoViewer.visible = true;
			videoViewer.src = attachment.tableList[index].uri;
		};

		// 获取文件信息
		const getFileIcon = (name: string) => {
			return "local-icon-" + getFileInfo(name, true)['iconName'];
		};

        // 下载文件
		const downloadFile = (index: number) => {
			return [getUrl(attachment.tableList[index].url), attachment.tableList[index].name,true];
		};

		/** 监听 **/

		// 监听全选
		watch(selectAll, () => {
			if (selectAll.value) {
				const keys = Object.keys(toRaw(selectedFile));
				attachment.tableList.forEach((item: Record<string, any>) => {
					if (!keys.includes(item.att_id)) selectedFile[item.att_id] = toRaw(item);
				});
			} else {
				clearSelected();
			}
		});

		// 监听分类切换
		watch(
			() => attachment.queryParams.cid,
			() => {
				getAttachmentList();
			}
		);

		// 监听选中的文件
		watch(selectedFile, () => {
			batchOperateDisabled.value = Object.keys(toRaw(selectedFile)).length == 0;
		});

		// 页面加载时
		onMounted(() => {
			initScene();
			getAttachmentCategoryList();
			getAttachmentList();
		});

		return {
			// 数据
			operate,
			getAccept,
			selectedFile,
			selectedFileOrder,
			selectedFileCount,
			attachmentCategory,
			attachmentCategoryTree,
			attachmentCategorySelect,
			defaultTreeProps,
			defaultSelectTreeProps,
			attachment,
			pageData,
			uploadRef,
			selectAll,
			moveAttachmentData,
			renameAttachmentData,
			batchOperateDisabled,
			renameFile,
			imageViewer,
			videoViewer,
			// 方法
			getAttachmentCategoryList,
			getAttachmentList,
			addAttachmentCategory,
			updateAttachmentCategory,
			deleteAttachmentCategory,
			attachmentCategoryChange,
			handleCatSelect,
			upload,
			clearSelected,
			selectFile,
			deleteAttachmentEvent,
			moveAttachmentEvent,
			moveAttachmentChange,
			previewImage,
			previewImageList,
			previewVideo,
			downloadFile,
			getFileIcon
		};
	},
});
</script>

<style lang="scss" scoped>
.attachment-content {
	display: flex;
	border-top-width: 1px;
	border-bottom-width: 1px;
	width: 100%;
	height: 46vh;
	border-color: var(--el-border-color);

	.attachment-content-left {
		display: flex;
		flex-direction: column;
		border-right-width: 1px;
		width: 200px;
		padding: 15px;
		height: 100%;
		border-color: var(--el-border-color);

		.cate-list {
			.el-tree {
				height: 260px;
				.el-tree-node.is-current {
					background-color: var(--el-color-primary-light-9);
					color: var(--el-color-primary);
				}
				.el-tree-node__content {
					width: 100%;
					height: 36px;
				}
				.el-tree-node__content:hover {
					background-color: var(--el-color-primary-light-9);
				}
			}
			.cate-item {
				cursor: pointer !important;
				font-size: var(--el-font-size-extra-small);
				padding: 10px 0;
				line-height: 36px;
				width: 100%;
			}
		}
	}
}

.attachment-list-wrap {
	.attachment-wrap {
		background: var(--el-border-color-extra-light);
	}

	.attachment-action {
		height: 16px;
		position: absolute;
		bottom: 10px;
		display: none;
	}

	.attachment-action span {
		color: #1890ff;
		font-size: 12px;
		white-space: nowrap;
		cursor: pointer;
	}

	.attachment-item .item-selected {
		display: flex;
		position: absolute;
		--tw-bg-opacity: 0.5;
		justify-content: center;
		align-items: center;
		width: 100%;
		height: 100%;
		inset: 0px;
		z-index: 1;
		background-color: #00000080;
	}

	.attachment-item .item-selected-badge {
		position: absolute;
		top: 8px;
		right: 4px;
		z-index: 2;
		::v-deep(.el-badge__content) {
			border: none;
		}
	}

	.attachment-item:hover {
		.attachment-action {
			display: block;
		}
	}

	.delete-all-btn {
		vertical-align: baseline;
		font-size: var(--el-font-size-extra-small);
	}
}

.el-upload-list {
	position: absolute !important;
	z-index: 10;

	.el-upload-list__item {
		background: #fff !important;
		box-shadow: var(--el-box-shadow-light);
	}
}
</style>